package com.yuan.springcloud.order.controller;

import com.alibaba.fastjson.JSON;
import com.yuan.springcloud.order.bean.ProductVO;
import com.yuan.springcloud.order.beanmapper.ProductMapper;
import com.yuan.springcloud.order.entity.Product;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author YouYuan
 * @date 2022/4/7 22:38
 */
@RestController
@RequestMapping("/test")
public class TestController {


    public static final Map<String, List<Product>> CACHE = new HashMap<>();
    public static final String KEY = "data";
    public static final int RETRY_MAX = 5;

    public static LongAdder cacheCount = new LongAdder();
    public static LongAdder missCount = new LongAdder();

    static {
        extracted();
    }

    private static void extracted() {
        List<Product> list = new ArrayList<>(1000);
        for (int i = 0; i < 1000; i++) {
            Product product = new Product();
            product.setProductName("产品：" + i);
            product.setProductDesc(Math.random()+ "");
            product.setPrice(BigDecimal.valueOf(i * Math.random() * 100));
            product.setInventory(i * 1000);
            product.setId((long) (i*199)+1000);
            product.setCaption("性能测试Json&Mapper：" + i);
            list.add(product);
        }
        CACHE.put(KEY, list);
    }

    @GetMapping("/cleanCache")
    public String cleanCache() {
        CACHE.clear();
        return "clean Cache ok";
    }
    @GetMapping("/setCache")
    public String setCache() {
        extracted();
        return "set Cache ok";
    }
    @GetMapping("/count")
    public List<Long> count() {
        return Arrays.asList(cacheCount.longValue(), missCount.longValue());
    }
    @GetMapping("/cleanCount")
    public String cleanCount() {
        cacheCount.reset();
        missCount.reset();
        return "clean Count ok";
    }

    @GetMapping("/testJson")
    public List<ProductVO> testJson() {
        List<Product> list = CACHE.get(KEY);
        List<ProductVO> voList = JSON.parseArray(JSON.toJSONString(list), ProductVO.class);
        return voList;
    }

    @GetMapping("/testMapper")
    public List<ProductVO> testMapper() {
        List<Product> list = CACHE.get(KEY);
        List<ProductVO> voList = ProductMapper.INSTANSE.productList2Vo(list);
        return voList;
    }

    @GetMapping("/testSpinlock")
    public List<ProductVO> testSpinlock() {
        int retry = 0;
        /**
         * 自旋判断缓存是否可用
         */
        while (retry < RETRY_MAX) {
            List<Product> list = CACHE.get(KEY);
            if (list != null) {
                cacheCount.increment();
                List<ProductVO> voList = ProductMapper.INSTANSE.productList2Vo(list);
                return voList;
            } else {
                retry++;
                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        /**
         * 缓存未命中，加载数据并放入缓存
         */
        extracted();
        List<Product> list = CACHE.get(KEY);
        List<ProductVO> voList = ProductMapper.INSTANSE.productList2Vo(list);
        missCount.increment();
        return voList;
    }

    @GetMapping("/testCache")
    public List<ProductVO> testCache() {
        List<Product> list = CACHE.get(KEY);
        if (list != null) {
            cacheCount.increment();
            List<ProductVO> voList = ProductMapper.INSTANSE.productList2Vo(list);
            return voList;
        } else {
            missCount.increment();
            extracted();
            list = CACHE.get(KEY);
            List<ProductVO> voList = ProductMapper.INSTANSE.productList2Vo(list);
            return voList;
        }
    }

    public static void main(String[] args) {
        int size = 10000;
        long s = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            List<Product> list = CACHE.get(KEY);
            List<ProductVO> voList = JSON.parseArray(JSON.toJSONString(list), ProductVO.class);
//            System.out.println(voList.get(i % voList.size()).getProductName());
//            voList.get(i % voList.size()).setStatus(2);
        }
        long e = System.currentTimeMillis();
        long jsonTime = e - s;

        s = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            List<Product> list = CACHE.get(KEY);
            List<ProductVO> voList = ProductMapper.INSTANSE.productList2Vo(list);
//            System.out.println(voList.get(i % voList.size()).getProductName());
//            voList.get(i % voList.size()).setStatus(2);
        }
        e = System.currentTimeMillis();

        /**
         * JSON use time:16177(ms)
         * Mapstruct use time:137(ms)
         */
        System.out.printf("JSON use time:%d(ms)%n", jsonTime);
        System.out.printf("Mapstruct use time:%d(ms)%n", (e-s));
    }
}
